
#include "Debug.h"
#include "simple_protocol.h"
#include <Reader/ReaderISO14443.h>


/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443A_GetATS = 0x00,
/*
Command: [1200][Byte: MaxATSByteCnt]
Response: [00][Bool: Result][Byte Array(Var): ATS]
*/
static int api_ISO14443A_GetATS(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t MaxATSByteCnt;
	}ISO14443A_GetATS_param_t;
	ISO14443A_GetATS_param_t *param = (ISO14443A_GetATS_param_t*)command->data;
	LOG_D("\nMaxATSByteCnt=%d", param->MaxATSByteCnt);
	uint8_t* ats = net_buf_simple_tail(response);
	uint8_t alen = 0;
	int ret = Reader_ISO14443A_GetATS(ats, &alen);
	API_CHECK(ret);
	if(alen > param->MaxATSByteCnt){
		alen = param->MaxATSByteCnt;
	}
	net_buf_simple_add(response, alen);
	net_buf_simple_push_u8(response, alen);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443B_GetATQB = 0x01,
/*
Command: [1201][Byte: MaxATQBByteCnt]
Response: [00][Bool: Result][Byte Array(Var): ATQB]
*/
static int api_ISO14443B_GetATQB(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t MaxATQBByteCnt;
	}ISO14443B_GetATS_param_t;
	ISO14443B_GetATS_param_t *param = (ISO14443B_GetATS_param_t*)command->data;
	LOG_D("\n MaxATQBByteCnt=%d", param->MaxATQBByteCnt);
	uint8_t* atqb = net_buf_simple_tail(response);
	uint8_t alen = 0;
	int ret = Reader_ISO14443B_GetATQB(atqb, &alen);
	API_CHECK(ret);
	if(alen > param->MaxATQBByteCnt){
		alen = param->MaxATQBByteCnt;
	}
	net_buf_simple_add(response, alen);
	net_buf_simple_push_u8(response, alen);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443_4_CheckPresence = 0x02,
/*
Command: [1202]
Response: [00][Bool: Result]
*/
static int api_ISO14443_4_CheckPresence(buffer_t* command, buffer_t* response){
	int ret = Reader_ISO14443_4_CheckPresence();
	if(ret){
		return ERR_NONE;
	}
	return -1;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443_4_TDX = 3,
/*
Command: [1203][Byte Array(Var): TX][Byte: MaxRXByteCnt]
Response: [00][Bool: Result][Byte Array(Var): RX]
*/
typedef struct {
	uint8_t ByteCnt;
	uint8_t *Data;
	uint8_t MaxRXByteCnt;
}ISO14443_4_TDX_param_t;

static void get_command_param_ISO14443_4_TDX(buffer_t* command, ISO14443_4_TDX_param_t* param){
	param->ByteCnt = net_buf_simple_pull_u8(command);
	param->Data = net_buf_simple_pull_mem(command, param->ByteCnt);
	param->MaxRXByteCnt = net_buf_simple_pull_u8(command);
}

static int api_ISO14443_4_TDX(buffer_t* command, buffer_t* response){
	ISO14443_4_TDX_param_t param;
	get_command_param_ISO14443_4_TDX(command, &param);
	LOG_D("\nByteCnt=%d, MaxATSByteCnt=%d", param.ByteCnt, param.MaxRXByteCnt);
	LOG_B("\nData", param.Data, param.ByteCnt, 16);
	uint8_t* rapdu = net_buf_simple_tail(response);
	uint16_t rlen = 0;
	uint16_t room = net_buf_simple_tailroom(response);
	int ret = Reader_ISO14443_4_Exchange(param.Data, param.ByteCnt, rapdu, &rlen, room);
	API_CHECK(ret);
	LOG_B("\nrapdu", rapdu, rlen, 16);
	if(rlen > param.MaxRXByteCnt){
		rlen = param.MaxRXByteCnt;
	}
	net_buf_simple_add(response, rlen);
	net_buf_simple_push_u8(response, rlen);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443A_GetATQA = 0x04,
/*
Command: [1204]
Response: [00][Bool: Result][Byte Array(2): ATQA]
*/
static int api_ISO14443A_GetATQA(buffer_t* command, buffer_t* response){
	uint8_t* atqa = net_buf_simple_tail(response);
	int ret = Reader_ISO14443A_GetATQA(atqa);
	API_CHECK(ret);
	net_buf_simple_add(response, 2);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443A_GetSAK = 0x05,
/*
Command: [1205]
Response: [00][Bool: Result][Byte Array(1): SAK]
*/
static int api_ISO14443A_GetSAK(buffer_t* command, buffer_t* response){
	uint8_t* sak = net_buf_simple_tail(response);
	int ret = Reader_ISO14443A_GetSAK(sak);
	API_CHECK(ret);
	net_buf_simple_add(response, 1);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443B_GetAnswerToATTRIB = 0x06,
/*
Command: [1206][Byte: MaxAnswerToATTRIBByteCnt]
Response: [00][Bool: Result][Byte Array(Var): AnswerToATTRIB]
*/
static int api_ISO14443B_GetAnswerToATTRIB(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t MaxAnswerToATTRIBByteCnt;
	}ISO14443B_GetAnswerToATTRIB_param_t;
	ISO14443B_GetAnswerToATTRIB_param_t *param = (ISO14443B_GetAnswerToATTRIB_param_t*)command->data;
	LOG_D("\n MaxAnswerToATTRIBByteCnt=%d", param->MaxAnswerToATTRIBByteCnt);
	uint8_t* rattrib = net_buf_simple_tail(response);
	uint8_t rlen = 0;
	int ret = Reader_ISO14443B_GetAnswerToATTRIB(rattrib, &rlen);
	API_CHECK(ret);
	if(rlen > param->MaxAnswerToATTRIBByteCnt){
		rlen = param->MaxAnswerToATTRIBByteCnt;
	}
	net_buf_simple_add(response, rlen);
	net_buf_simple_push_u8(response, rlen);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443_4_TDX = 3,
/*
Command: [1207][Byte Array(Var): TX][Byte: MaxRXByteCnt][UInt16: Timeout]
Response: [00][Bool: Result][Byte Array(Var): RX]
*/
typedef struct {
	uint8_t ByteCnt;
	uint8_t *Data;
	uint8_t MaxRXByteCnt;
	uint16_t Timeout;
}ISO14443_3_TDX_param_t;

static void get_command_param_ISO14443_3_TDX(buffer_t* command, ISO14443_3_TDX_param_t* param){
	param->ByteCnt = net_buf_simple_pull_u8(command);
	param->Data = net_buf_simple_pull_mem(command, param->ByteCnt);
	param->MaxRXByteCnt = net_buf_simple_pull_u8(command);
	param->Timeout = net_buf_simple_pull_be16(command);
}

static int api_ISO14443_3_TDX(buffer_t* command, buffer_t* response){
	ISO14443_3_TDX_param_t param;
	get_command_param_ISO14443_3_TDX(command, &param);
	LOG_D("\nMaxRXByteCnt=%d, Timeout=%d", param.MaxRXByteCnt, param.Timeout);
	LOG_B("\nData", param.Data, param.ByteCnt, 16);
	uint8_t* rbuf = net_buf_simple_tail(response);
	uint16_t rlen = 0;
	uint16_t room = net_buf_simple_tailroom(response);
	int ret = Reader_ISO14443_3_Exchange(param.Data, param.ByteCnt, rbuf, &rlen, room, param.Timeout);
	API_CHECK(ret);
	LOG_B("\nrbuf", rbuf, rlen, 16);
	if(rlen > param.MaxRXByteCnt){
		rlen = param.MaxRXByteCnt;
	}
	net_buf_simple_add(response, rlen);
	net_buf_simple_push_u8(response, rlen);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443A_SearchMultiTag = 0x08,
/*
Command: [1208][Byte: MaxUIDListByteCnt]
Response: [00][Bool: Result][Byte: UIDCnt][variable number of Bytes: UIDList]
*/
static int api_ISO14443A_SearchMultiTag(buffer_t* command, buffer_t* response){
	return ERR_INVALID_FUNCTION;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_ISO14443A_SearchMultiTag = 0x09,
/*
Command: [1209][Byte Array(Var): UID]
Response: [00][Bool: Result]
*/
static int api_ISO14443A_SelectTag(buffer_t* command, buffer_t* response){
	return ERR_INVALID_FUNCTION;
}

/*--------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------*/
enum {
	API_ISO14443A_GetATS = 0,
	API_ISO14443B_GetATQB = 1,
	API_ISO14443_4_CheckPresence = 2,
	API_ISO14443_4_TDX = 3,
	API_ISO14443A_GetATQA	= 4,
	API_ISO14443A_GetSAK = 5,
	API_ISO14443B_GetAnswerToATTRIB = 6,
	API_ISO14443_3_TDX = 7,
	API_ISO14443A_SearchMultiTag = 8,
	API_ISO14443A_SelectTag = 9,
	API_ISO14443_NUM,
};

static const api_entry_t api_iso14443_list[API_ISO14443_NUM] = {
	[API_ISO14443A_GetATS] 				= api_ISO14443A_GetATS,
	[API_ISO14443B_GetATQB] 			= api_ISO14443B_GetATQB,
	[API_ISO14443_4_CheckPresence] 		= api_ISO14443_4_CheckPresence,
	[API_ISO14443_4_TDX]				= api_ISO14443_4_TDX,
	[API_ISO14443A_GetATQA]				= api_ISO14443A_GetATQA,
	[API_ISO14443A_GetSAK]				= api_ISO14443A_GetSAK,
	[API_ISO14443B_GetAnswerToATTRIB]	= api_ISO14443B_GetAnswerToATTRIB,
	[API_ISO14443_3_TDX]				= api_ISO14443_3_TDX,
	[API_ISO14443A_SearchMultiTag] 		= api_ISO14443A_SearchMultiTag,
	[API_ISO14443A_SelectTag]			= api_ISO14443A_SelectTag,
};
	
static int iso14443_api(buffer_t* command, buffer_t* response){
	const uint8_t num = sizeof(api_iso14443_list)/sizeof(api_iso14443_list[0]);
	int ret = protocol_call_api(api_iso14443_list, num, command, response);
	if(ret > 0){
		return ret;
	}
	protocol_response_result(response, ret);
	return ERR_NONE;
}

SIMPLE_API_DEFINE(API_CLASS_ISO14443, iso14443_api);


